package org.dromara.hm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.hm.domain.HmPaymentAdjustment;
import org.dromara.hm.domain.HmSaleOrderPickUp;
import org.dromara.hm.domain.HmTodoItems;
import org.dromara.hm.domain.bo.HmPaymentAdjustmentBo;
import org.dromara.hm.domain.vo.HmPaymentAdjustmentVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderVo;
import org.dromara.hm.enums.OrderStatus;
import org.dromara.hm.enums.PaymentAdjustmentStatusEnum;
import org.dromara.hm.enums.PaymentAdjustmentTypeEnum;
import org.dromara.hm.enums.PickUpStatusEnum;
import org.dromara.hm.enums.ToDoTypeEnum;
import org.dromara.hm.mapper.HmPaymentAdjustmentMapper;
import org.dromara.hm.mapper.HmTodoItemsMapper;
import org.dromara.hm.service.IHmPaymentAdjustmentService;
import org.dromara.hm.service.IHmSaleOrderService;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDeptService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 回款调整记录Service业务层处理
 *
 * @author Claude Code
 * @date 2025-01-16
 */
@RequiredArgsConstructor
@Service
public class HmPaymentAdjustmentServiceImpl implements IHmPaymentAdjustmentService {

    private final HmPaymentAdjustmentMapper baseMapper;
    private final IHmSaleOrderService hmSaleOrderService;
    private final ISysDeptService deptService;
    private final HmTodoItemsMapper todoItemsMapper;

    /**
     * 查询回款调整记录
     *
     * @param adjustmentId 主键
     * @return 回款调整记录
     */
    @Override
    public HmPaymentAdjustmentVo queryById(Long adjustmentId) {
        HmPaymentAdjustmentVo vo = baseMapper.selectVoById(adjustmentId);
        if (vo != null) {
            // 填充枚举描述
            vo.setAdjustmentTypeDesc(PaymentAdjustmentTypeEnum.getByCode(vo.getAdjustmentType()).getDescription());
            vo.setStatusDesc(PaymentAdjustmentStatusEnum.getByCode(vo.getStatus()).getDescription());

            // 查询订单信息
            HmSaleOrderVo saleOrder = hmSaleOrderService.queryById(vo.getSaleId());
            if (saleOrder != null) {
                vo.setCustomerName(saleOrder.getCustomerName());
                vo.setSaleAmount(saleOrder.getSaleAmount());
            }
        }
        return vo;
    }

    /**
     * 分页查询回款调整记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 回款调整记录分页列表
     */
    @Override
    public TableDataInfo<HmPaymentAdjustmentVo> queryPageList(HmPaymentAdjustmentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HmPaymentAdjustment> lqw = buildQueryWrapper(bo);
        Page<HmPaymentAdjustmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        // 填充额外信息
        result.getRecords().forEach(vo -> {
            // 填充枚举描述
            vo.setAdjustmentTypeDesc(PaymentAdjustmentTypeEnum.getByCode(vo.getAdjustmentType()).getDescription());
            vo.setStatusDesc(PaymentAdjustmentStatusEnum.getByCode(vo.getStatus()).getDescription());

            // 查询订单信息
            HmSaleOrderVo saleOrder = hmSaleOrderService.queryById(vo.getSaleId());
            if (saleOrder != null) {
                vo.setCustomerName(saleOrder.getCustomerName());
                vo.setSaleAmount(saleOrder.getSaleAmount());
            }
        });

        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的回款调整记录列表
     *
     * @param bo 查询条件
     * @return 回款调整记录列表
     */
    @Override
    public List<HmPaymentAdjustmentVo> queryList(HmPaymentAdjustmentBo bo) {
        LambdaQueryWrapper<HmPaymentAdjustment> lqw = buildQueryWrapper(bo);
        List<HmPaymentAdjustmentVo> list = baseMapper.selectVoList(lqw);

        // 填充额外信息
        list.forEach(vo -> {
            // 填充枚举描述
            vo.setAdjustmentTypeDesc(PaymentAdjustmentTypeEnum.getByCode(vo.getAdjustmentType()).getDescription());
            vo.setStatusDesc(PaymentAdjustmentStatusEnum.getByCode(vo.getStatus()).getDescription());

            // 查询订单信息
            HmSaleOrderVo saleOrder = hmSaleOrderService.queryById(vo.getSaleId());
            if (saleOrder != null) {
                vo.setCustomerName(saleOrder.getCustomerName());
                vo.setSaleAmount(saleOrder.getSaleAmount());
            }
        });

        return list;
    }

    private LambdaQueryWrapper<HmPaymentAdjustment> buildQueryWrapper(HmPaymentAdjustmentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HmPaymentAdjustment> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getAdjustmentId() != null, HmPaymentAdjustment::getAdjustmentId, bo.getAdjustmentId());
        lqw.eq(bo.getSaleId() != null, HmPaymentAdjustment::getSaleId, bo.getSaleId());
        lqw.eq(StringUtils.isNotBlank(bo.getAdjustmentType()), HmPaymentAdjustment::getAdjustmentType, bo.getAdjustmentType());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), HmPaymentAdjustment::getStatus, bo.getStatus());
        lqw.eq(bo.getApplicantId() != null, HmPaymentAdjustment::getApplicantId, bo.getApplicantId());
        lqw.eq(bo.getApproverId() != null, HmPaymentAdjustment::getApproverId, bo.getApproverId());
        lqw.between(bo.getApplyStartTime() != null && bo.getApplyEndTime() != null,
            HmPaymentAdjustment::getApplyTime, bo.getApplyStartTime(), bo.getApplyEndTime());
        lqw.between(bo.getApproveStartTime() != null && bo.getApproveEndTime() != null,
            HmPaymentAdjustment::getApproveTime, bo.getApproveStartTime(), bo.getApproveEndTime());
        lqw.orderByDesc(HmPaymentAdjustment::getApplyTime);
        return lqw;
    }

    /**
     * 申请回款调整
     *
     * @param bo 回款调整记录
     * @return 是否申请成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean applyAdjustment(HmPaymentAdjustmentBo bo) {
        // 1. 查询原订单信息
        HmSaleOrderVo saleOrder = hmSaleOrderService.queryById(bo.getSaleId());
        if (saleOrder == null) {
            throw new ServiceException("销售订单不存在");
        }

        // 2. 计算调整前后的未回款金额
        BigDecimal originalUnpaid = saleOrder.getRefundSurplusNum();
        if (originalUnpaid == null) {
            originalUnpaid = BigDecimal.ZERO;
        }

        // 调整金额为正数表示减少未回款，为负数表示增加未回款
        BigDecimal newUnpaid = originalUnpaid.subtract(bo.getAdjustmentAmount());

        if (newUnpaid.compareTo(BigDecimal.ZERO) < 0) {
            throw new ServiceException("调整后的未回款金额不能为负数");
        }

        // 3. 创建调整记录
        HmPaymentAdjustment adjustment = MapstructUtils.convert(bo, HmPaymentAdjustment.class);
        adjustment.setOriginalUnpaidAmount(originalUnpaid);
        adjustment.setNewUnpaidAmount(newUnpaid);
        adjustment.setApplyTime(new Date());
        adjustment.setApplicantId(LoginHelper.getUserId());
        adjustment.setApplicantName(LoginHelper.getUsername());
        adjustment.setStatus(PaymentAdjustmentStatusEnum.PENDING.getCode());

        // 处理证明材料文件列表
        if (ObjectUtil.isNotEmpty(bo.getProofFileList())) {
            adjustment.setProofFiles(String.join(",", bo.getProofFileList()));
        }

        boolean flag = baseMapper.insert(adjustment) > 0;
        if (flag) {
            bo.setAdjustmentId(adjustment.getAdjustmentId());
        }

        // 4. 创建待办事项（发送给财务主管审核）
        createAdjustmentTodoItem(adjustment, saleOrder);

        return flag;
    }

    /**
     * 审核回款调整申请（批准）
     *
     * @param adjustmentId  调整记录ID
     * @param approveRemark 审核备注
     * @return 是否审核成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approveAdjustment(Long adjustmentId, String approveRemark) {
        // 1. 查询调整记录
        HmPaymentAdjustment adjustment = baseMapper.selectById(adjustmentId);
        if (adjustment == null) {
            throw new ServiceException("调整记录不存在");
        }

        if (!PaymentAdjustmentStatusEnum.PENDING.getCode().equals(adjustment.getStatus())) {
            throw new ServiceException("只能审核待审核状态的记录");
        }

        // 2. 更新调整记录状态
        adjustment.setStatus(PaymentAdjustmentStatusEnum.APPROVED.getCode());
        adjustment.setApproverId(LoginHelper.getUserId());
        adjustment.setApproverName(LoginHelper.getUsername());
        adjustment.setApproveTime(new Date());
        adjustment.setApproveRemark(approveRemark);
        baseMapper.updateById(adjustment);

        // 3. 更新订单的未回款金额（通过在回款表中插入一条特殊的调整记录）
        // 注意：这里我们不直接修改订单的refundSurplusNum字段，而是通过回款记录来影响计算结果
        // 这样可以保持数据的一致性和可追溯性

        // 4. 完成待办事项
        completeTodoItem(adjustment);

        return true;
    }

    /**
     * 驳回回款调整申请
     *
     * @param adjustmentId  调整记录ID
     * @param rejectReason  驳回原因
     * @return 是否驳回成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rejectAdjustment(Long adjustmentId, String rejectReason) {
        // 1. 查询调整记录
        HmPaymentAdjustment adjustment = baseMapper.selectById(adjustmentId);
        if (adjustment == null) {
            throw new ServiceException("调整记录不存在");
        }

        if (!PaymentAdjustmentStatusEnum.PENDING.getCode().equals(adjustment.getStatus())) {
            throw new ServiceException("只能驳回待审核状态的记录");
        }

        // 2. 更新调整记录状态
        adjustment.setStatus(PaymentAdjustmentStatusEnum.REJECTED.getCode());
        adjustment.setApproverId(LoginHelper.getUserId());
        adjustment.setApproverName(LoginHelper.getUsername());
        adjustment.setApproveTime(new Date());
        adjustment.setApproveRemark(rejectReason);
        baseMapper.updateById(adjustment);

        // 3. 完成待办事项（标记为已处理）
        completeTodoItem(adjustment);

        return true;
    }

    /**
     * 取消回款调整申请
     *
     * @param adjustmentId 调整记录ID
     * @return 是否取消成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelAdjustment(Long adjustmentId) {
        // 1. 查询调整记录
        HmPaymentAdjustment adjustment = baseMapper.selectById(adjustmentId);
        if (adjustment == null) {
            throw new ServiceException("调整记录不存在");
        }

        // 只有待审核状态才能取消
        if (!PaymentAdjustmentStatusEnum.PENDING.getCode().equals(adjustment.getStatus())) {
            throw new ServiceException("只能取消待审核状态的记录");
        }

        // 只有申请人自己才能取消
        if (!adjustment.getApplicantId().equals(LoginHelper.getUserId())) {
            throw new ServiceException("只有申请人才能取消申请");
        }

        // 2. 更新调整记录状态
        adjustment.setStatus(PaymentAdjustmentStatusEnum.CANCELLED.getCode());
        baseMapper.updateById(adjustment);

        // 3. 取消待办事项
        cancelTodoItem(adjustment);

        return true;
    }

    /**
     * 修改回款调整记录
     *
     * @param bo 回款调整记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HmPaymentAdjustmentBo bo) {
        HmPaymentAdjustment update = MapstructUtils.convert(bo, HmPaymentAdjustment.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HmPaymentAdjustment entity) {
        // TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除回款调整记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 只能删除待审核或已驳回状态的记录
            List<HmPaymentAdjustment> adjustments = baseMapper.selectBatchIds(ids);
            for (HmPaymentAdjustment adjustment : adjustments) {
                if (PaymentAdjustmentStatusEnum.APPROVED.getCode().equals(adjustment.getStatus())) {
                    throw new ServiceException("已批准的调整记录不能删除");
                }
            }
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 创建待办事项
     *
     * @param adjustment 调整记录
     * @param saleOrder  销售订单
     */
    private void createAdjustmentTodoItem(HmPaymentAdjustment adjustment, HmSaleOrderVo saleOrder) {
        // 查询财务主管或店长
        List<SysUserVo> sysUserVos = deptService.selectUserListByDeptIdAndRoleId(saleOrder.getSaleDept(), 1869282439378976770L);// 店长角色
        if (ObjectUtil.isEmpty(sysUserVos)) {
            // 如果没有店长，则发给超级管理员
            sysUserVos = List.of();
        }

        HmTodoItems hmTodoItemsBo = new HmTodoItems();
        hmTodoItemsBo.setTodoType(ToDoTypeEnum.PAYMENT_ADJUSTMENT.getCode());
        hmTodoItemsBo.setTodoDesc(String.format("订单[%s]申请回款调整，调整类型：%s，调整金额：%s",
            saleOrder.getSaleId(),
            PaymentAdjustmentTypeEnum.getByCode(adjustment.getAdjustmentType()).getDescription(),
            adjustment.getAdjustmentAmount()));
        hmTodoItemsBo.setCreateType("1"); // 系统生成
        hmTodoItemsBo.setOrderId(adjustment.getSaleId());
        hmTodoItemsBo.setStatus("0"); // 待处理

        // 使用 remark 字段存储调整记录ID，方便后续查找
        hmTodoItemsBo.setRemark("adjustmentId:" + adjustment.getAdjustmentId());

        // 设置提交人信息（申请人）
        hmTodoItemsBo.setSubmitterId(adjustment.getApplicantId());
        hmTodoItemsBo.setSubmitterName(adjustment.getApplicantName());

        if (ObjectUtil.isNotEmpty(sysUserVos)) {
            hmTodoItemsBo.setTodoPersonId(sysUserVos.get(0).getUserId());
            hmTodoItemsBo.setTodoPersonName(sysUserVos.get(0).getNickName());
            hmTodoItemsBo.setTodoStockDept(saleOrder.getSaleDept());
            // 设置审核人
            hmTodoItemsBo.setApproverId(sysUserVos.get(0).getUserId());
            hmTodoItemsBo.setApproverName(sysUserVos.get(0).getNickName());
        } else {
            // 默认给超级管理员
            hmTodoItemsBo.setTodoPersonId(1L);
            hmTodoItemsBo.setTodoPersonName("超级管理员");
            // 设置审核人为超级管理员
            hmTodoItemsBo.setApproverId(1L);
            hmTodoItemsBo.setApproverName("超级管理员");
        }

        todoItemsMapper.insert(hmTodoItemsBo);
    }

    /**
     * 完成待办事项
     *
     * @param adjustment 调整记录
     */
    private void completeTodoItem(HmPaymentAdjustment adjustment) {
        // 查询待办事项
        LambdaQueryWrapper<HmTodoItems> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(HmTodoItems::getOrderId, adjustment.getSaleId());
        wrapper.eq(HmTodoItems::getTodoType, ToDoTypeEnum.PAYMENT_ADJUSTMENT.getCode());
        wrapper.eq(HmTodoItems::getStatus, "0"); // 待处理
        List<HmTodoItems> todoItems = todoItemsMapper.selectList(wrapper);

        if (ObjectUtil.isNotEmpty(todoItems)) {
            HmTodoItems todoItem = todoItems.get(0);
            todoItem.setStatus("1"); // 已完成
            todoItem.setTodoResult(PaymentAdjustmentStatusEnum.getByCode(adjustment.getStatus()).getDescription());
            todoItem.setTodoCompletionTime(new Date());
            todoItemsMapper.updateById(todoItem);
        }
    }

    /**
     * 取消待办事项
     *
     * @param adjustment 调整记录
     */
    private void cancelTodoItem(HmPaymentAdjustment adjustment) {
        // 查询待办事项
        LambdaQueryWrapper<HmTodoItems> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(HmTodoItems::getOrderId, adjustment.getSaleId());
        wrapper.eq(HmTodoItems::getTodoType, ToDoTypeEnum.PAYMENT_ADJUSTMENT.getCode());
        wrapper.eq(HmTodoItems::getStatus, "0"); // 待处理
        List<HmTodoItems> todoItems = todoItemsMapper.selectList(wrapper);

        if (ObjectUtil.isNotEmpty(todoItems)) {
            HmTodoItems todoItem = todoItems.get(0);
            todoItem.setStatus("2"); // 已取消
            todoItem.setTodoResult("申请人已取消");
            todoItem.setTodoCompletionTime(new Date());
            todoItemsMapper.updateById(todoItem);
        }
    }
}
